#include <sys_config.h>

#ifdef DISK_MANAGER_SUPPORT

#include <types.h>
#include <basic_types.h>
#include <mediatypes.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <osal/osal.h>
#include <api/libmp/lib_mp.h>
#include <api/libmp/pe.h>
#include <api/libfs2/statvfs.h>
#include <api/libvfs/vfs.h>
#include <api/libfs2/fs_main.h>
#include <api/libvfs/device.h>

#include "osdobjs_def.h"
#include "images.id"
#include "string.id"
#include "osd_config.h"

#include "control.h"
#include "menus_root.h"
#include "win_com.h"
#include "win_com_popup.h"
#include "win_com_list.h"
#include "disk_manager.h"
#include "win_disk_operate.h"
#include "./platform/board.h"

/******************************************************************************
 * Debug macro define
 ******************************************************************************/
#define DM_DEBUG_NONE			0
#define DM_DEBUG_NORMAL			(1 << 0)
#define DM_DEBUG_MALLOC_FREE	(1 << 1)

#define DM_DEBUG_LEVEL			DM_DEBUG_NONE

#if (DM_DEBUG_LEVEL & DM_DEBUG_NORMAL)
#define DM_DEBUG(fmt, arg...) libc_printf(fmt, ##arg)
#define DM_ERROR(fmt, arg...) \
    do { \
        libc_printf("Error: %s line %d: "fmt, __FILE__, __LINE__, ##arg); \
        SDBBP(); \
    } while (0)
#else
#define DM_DEBUG(...)		do{} while(0)
#define DM_ERROR(...)		do{} while(0)
#endif

#if (DM_DEBUG_LEVEL & DM_DEBUG_MALLOC_FREE)
int dm_malloc_cnt = 0;
#endif

#if defined(SUPPORT_VMX_STD) || defined(SUPPORT_VMX)
#if 0
#define VMX_API_PRINTF		libc_printf
#else
#define VMX_API_PRINTF(...)	do{}while(0)
#endif
#endif
/******************************************************************************/
int diskType2NamePrefix(int disk_type, char *name, int len)
{
	int ret = 0;
	if (len < 3)
	{
		STRCPY(name, "");
		return -1;
	}
	
	switch (disk_type)
	{
		case MNT_TYPE_USB:
			STRCPY(name, "ud");
			break;
		case MNT_TYPE_SD:
			STRCPY(name, "sd");
			break;
		case MNT_TYPE_IDE:
			STRCPY(name, "hd");
			break;
		case MNT_TYPE_SATA:
			STRCPY(name, "sh");
			break;
		default:
			STRCPY(name, "");
			ret = -1;
			break;
	}
	return ret;
}

int diskNamePrefix2Type(char *name)
{
	int disk_type;
	
	if (strncmp(name, "ud", 2) == 0)
		disk_type = MNT_TYPE_USB;
	else if (strncmp(name, "sd", 2) == 0)
		disk_type = MNT_TYPE_SD;
	else if (strncmp(name, "hd", 2) == 0)
		disk_type = MNT_TYPE_IDE;
	else if (strncmp(name, "sh", 2) == 0)
		disk_type = MNT_TYPE_SATA;
	else
		disk_type = -1; // invalid disk type
		
	return disk_type;
}

/******************************************************************************
 * disk manager
 ******************************************************************************/
static DiskMgr g_dm; /* disk manager */

#define DMLock() 	osal_mutex_lock(g_dm.MutexId, OSAL_WAIT_FOREVER_TIME)
#define DMUnlock()  osal_mutex_unlock(g_dm.MutexId)

static PedFileSystemType dm_get_fs_type(const char *vol_path)
{
	struct statvfs buf;

	if (fs_statvfs(vol_path, &buf) < 0)
	{
		DM_DEBUG("Get %s file system type failed!\n", vol_path);
		return PED_FS_TYPE_NONE;
	}
	else
	{
		if (STRCMP(buf.f_fsh_name, "FAT12") == 0)
			return PED_FS_TYPE_FAT12;
		else if (STRCMP(buf.f_fsh_name, "FAT16") == 0)
			return PED_FS_TYPE_FAT16;
		else if (STRCMP(buf.f_fsh_name, "FAT32") == 0)
			return PED_FS_TYPE_FAT32;
		else if (STRCMP(buf.f_fsh_name, "NTFS") == 0)
			return PED_FS_TYPE_NTFS;
		else
			return PED_FS_TYPE_NONE;
	}
}


int dm_init(void)
{
	MEMSET(&g_dm, 0, sizeof(DiskMgr));
	if ((g_dm.MutexId = osal_mutex_create()) == OSAL_INVALID_ID)
	{
		DM_ERROR("Create mutex failed!\n");
		return -1;
	}

	return 0;
}

static int dm_update(UINT32 dev_type, UINT32 dev_id)
{
	char disk_name[8];
	char dev_path[16];
	char vol_path[16];
	DiskInfo *p_disk = NULL;
	DiskInfo **pp_disk = NULL;
	int ret = -1;
	
	if (((dev_type == MNT_TYPE_USB) && (dev_id >= MAX_USB_DISK_NUM)) ||
		((dev_type == MNT_TYPE_SD)  && (dev_id >= MAX_SD_DISK_NUM))  ||
		((dev_type == MNT_TYPE_SATA)  && (dev_id >= MAX_SATA_DISK_NUM))  ||
		((dev_type == MNT_TYPE_IDE) && (dev_id >= MAX_IDE_DISK_NUM)))
	{
		DM_ERROR("Unsupport device (%d, %d)\n", dev_type, dev_id);
		return ret;
	}

	DM_DEBUG("DM update device (%d, %d)\n", dev_type, dev_id);
	DMLock();

	do {
		switch (dev_type)
		{
			case MNT_TYPE_USB:
				sprintf(disk_name, "ud%c", dev_id+'a');
				pp_disk = &g_dm.UsbDisks[dev_id];
				break;
			case MNT_TYPE_SD:
				sprintf(disk_name, "sd%c", dev_id+'a');
				pp_disk = &g_dm.SdDisks[dev_id];
				break;
			case MNT_TYPE_IDE:
				sprintf(disk_name, "hd%c", dev_id+'a');
				pp_disk = &g_dm.IdeDisks[dev_id];
				break;
			case MNT_TYPE_SATA:
				sprintf(disk_name, "sh%c", dev_id+'a');
				pp_disk = &g_dm.SataDisks[dev_id];
				break;
			default:
				disk_name[0] = 0;
				break;
		}

		if (disk_name[0] == 0)
		{
			DM_DEBUG("Unknown device (%d, %d)\n", dev_type, dev_id);
			break;
		}

		if (*pp_disk != NULL)
		{
#if (DM_DEBUG_LEVEL & DM_DEBUG_MALLOC_FREE)
			dm_malloc_cnt--;
#endif
			FREE(*pp_disk);
			*pp_disk = NULL;
		}
		
		if ((p_disk = (DiskInfo *)MALLOC(sizeof(DiskInfo))) ==  NULL)
		{
#if (DM_DEBUG_LEVEL & DM_DEBUG_MALLOC_FREE)
			dm_malloc_cnt++;
#endif
			DM_DEBUG("Memory exhausted!\n", dev_type, dev_id);
			break;
		}

		MEMSET(p_disk, 0, sizeof(DiskInfo));
		sprintf(dev_path, "/dev/%s", disk_name);

		int fd, fd_dir;
		device_geometry geo;
		char dirbuf[sizeof(struct dirent) + 32];
		struct dirent *pdir = (struct dirent *)dirbuf;

		/* get disk info */
		fd = fs_open(dev_path, O_RDONLY, 0);
		if (fd < 0)
		{
			DM_DEBUG("device %s not exist!\n", dev_path);
			break;
		}
		
		if (fs_ioctl(fd, IOCTL_GET_DEVICE_GEOMETRY, &geo, sizeof(struct device_geometry)) < 0)
		{
			fs_close(fd);
			break;	
		}
		p_disk->DiskSize = geo.sector_count * geo.bytes_per_sector;
		fs_close(fd);
		
	    if ((fd_dir = fs_opendir("/dev")) < 0)
	    {
			DM_DEBUG("open /dev failed!\n");
			break;
	    }
		
		ret = 0; /* get necessary disk info successfully */

		int part_idx;
		while (fs_readdir(fd_dir, pdir) > 0)
		{
			/* find partitions */
	        if ((STRLEN(pdir->d_name) == 4) && (strncmp(pdir->d_name, disk_name, 3) == 0))
				
			{
				part_idx = pdir->d_name[3] - '1';
				if ((part_idx < 0) || (part_idx >= MAX_PARTS_IN_DISK))
				{
					continue;
				}
				sprintf(dev_path, "/dev/%s", pdir->d_name);
				sprintf(vol_path, "/mnt/%s", pdir->d_name);

				/* get part info */
				fd = fs_open(dev_path, O_RDONLY, 0);
				if (fs_ioctl(fd, IOCTL_GET_DEVICE_GEOMETRY, &geo, sizeof(struct device_geometry)) < 0)
				{
					fs_close(fd);
					continue;	
				}
				fs_close(fd);
				
				p_disk->parts[part_idx].PartExist = 1;
	 			p_disk->parts[part_idx].FileSystemType = dm_get_fs_type(vol_path);
				p_disk->parts[part_idx].PartSize = geo.sector_count * geo.bytes_per_sector;
				p_disk->part_num++;
				if (p_disk->parts[part_idx].FileSystemType != PED_FS_TYPE_NONE)
					p_disk->vol_num++;
			}
		}
		fs_closedir(fd_dir);
	} while(0);

	if (ret == 0)
	{
		*pp_disk = p_disk;
//		p_disk = NULL;
	}
	else if (p_disk != NULL)
	{
#if (DM_DEBUG_LEVEL & DM_DEBUG_MALLOC_FREE)
		dm_malloc_cnt--;
#endif
		FREE(p_disk);
	}

	DMUnlock();
	
	return ret;
}

int dm_ioctl(DM_CMD cmd, UINT32 param, void *buf, int len)
{
	DiskInfo **pp_disk;
	DiskInfo *p_disk;
	int i, j;
	int max_disk_num = 0;
	int ret = -1;
	UINT32 disk_type = DM_CMD_DISK_TYPE(param);
	UINT32 disk_idx  = DM_CMD_DISK_IDX(param);
	UINT32 part_idx  = DM_CMD_PART_IDX(param);

	switch (disk_type)
	{
		case MNT_TYPE_USB:
			pp_disk = g_dm.UsbDisks;
			max_disk_num = MAX_USB_DISK_NUM;
			break;
		case MNT_TYPE_SD:
			pp_disk = g_dm.SdDisks;
			max_disk_num = MAX_SD_DISK_NUM;
			break;
		case MNT_TYPE_IDE:
			pp_disk = g_dm.IdeDisks;
			max_disk_num = MAX_IDE_DISK_NUM;
			break;
		case MNT_TYPE_SATA:
			pp_disk = g_dm.SataDisks;
			max_disk_num = MAX_SATA_DISK_NUM;
			break;
		default:
			pp_disk = NULL;
			max_disk_num = 0;
			break;
	}

	if (pp_disk == NULL || max_disk_num == 0)
	{
		DM_DEBUG("%s() unknown disk type: %d\n", __FUNCTION__, disk_type);
		return -1;
	}

	DMLock();
	
	switch (cmd)
	{
		case DM_CMD1_GET_DISK_NUM:
		{
			int disk_num = 0;
			for (i = 0; i < max_disk_num; ++i)
			{				
				if ((p_disk = pp_disk[i]) != NULL)
				{
					disk_num++;
				}
			}
			
			if (buf && (len >= (int)sizeof(int)))
			{
				*(int *)buf = disk_num;
				ret = 0;
			}
			break;
		}
		case DM_CMD1_GET_PART_NUM:
		case DM_CMD1_GET_VOL_NUM:
		{
			int part_num = 0;
			int vol_num  = 0;
			for (i = 0; i < max_disk_num; ++i)
			{				
				if ((p_disk = pp_disk[i]) == NULL)
					continue;

				part_num += p_disk->part_num;
				vol_num  += p_disk->vol_num;
			}
			
			if (buf && (len >= (int)sizeof(int)))
			{
				if (cmd == DM_CMD1_GET_PART_NUM)
					*(int *)buf = part_num;
				else
					*(int *)buf = vol_num;
				ret = 0;
			}
			break;
		}
		case DM_CMD2_GET_DISK_SIZE:
		{
			p_disk = pp_disk[disk_idx];
			if ((p_disk != NULL) && buf && (len >= (int)sizeof(UINT64)))
			{
				*(UINT64 *)buf = p_disk->DiskSize;
				ret = 0;
			}
			break;
		}
		case DM_CMD2_GET_PART_NUM:
		case DM_CMD2_GET_VOL_NUM:
		{
			p_disk = pp_disk[disk_idx];
			if ((p_disk != NULL) && buf && (len >= (int)sizeof(int)))
			{
				if (cmd == DM_CMD2_GET_PART_NUM)
					*(int *)buf = p_disk->part_num;
				else
					*(int *)buf = p_disk->vol_num;
				ret = 0;
			}
			break;
		}
		case DM_CMD3_UPDATE_VOL_INFO:
		{
			p_disk = pp_disk[disk_idx];
			if ((p_disk != NULL) && p_disk->parts[part_idx].PartExist == 1)
			{
				char vol_path[16], tmp[8];
				diskType2NamePrefix(disk_type, tmp, 8);
				sprintf(vol_path, "/mnt/%s%c%c", tmp, disk_idx+'a', part_idx+'1');
				
				if (p_disk->parts[part_idx].FileSystemType != PED_FS_TYPE_NONE)
					p_disk->vol_num--;
	 			p_disk->parts[part_idx].FileSystemType = dm_get_fs_type(vol_path);
				if (p_disk->parts[part_idx].FileSystemType != PED_FS_TYPE_NONE)
					p_disk->vol_num++;
				ret = 0;
			}
			break;
		}
		default:
			break;
	}
	
	DMUnlock();
	return ret;
}


#if 0
/* check if the disk @disk_path is exist */
static BOOL dm_is_disk_exist(const char *disk_path)
{
	struct statvfs buf;

	if (strncmp(disk_path, "/dev/", 5) != 0)
		return FALSE;
	
	if (fs_statvfs(disk_path, &buf) < 0)
		return FALSE;
	else
		return TRUE;
}
#endif

/******************************************************************************
 * for media player
 ******************************************************************************/
static UINT8 mp_udisk_id = INVALID_UDISK_ID;

BOOL ap_mp_is_ready()
{
	return (mp_udisk_id != INVALID_UDISK_ID);
}

void ap_udisk_close()
{
#ifdef NEW_DEMO_FRAME
	if (mp_udisk_id != INVALID_UDISK_ID)
	{
		media_player_release();
		mp_udisk_id = INVALID_UDISK_ID;
		DM_DEBUG("release media player\n");
	}
#else
	if (udisk_close(mp_udisk_id) == RET_SUCCESS)
	{
		mp_udisk_id = INVALID_UDISK_ID;
		DM_DEBUG("media player release\n");
	}
#endif
}

#ifdef _BUILD_USB_LOADER_
RET_CODE win_media_player_init(mp_callback_func mp_cb)
{
	return 0;
}

void file_list_init_parameter()
{
}

void win_disk_info_update(BOOL disk_change)
{
}

void win_delete_filelist(UINT32 dev_id)
{
}
#endif

static int mp_disk_attach_proc()
{
	if (mp_udisk_id == INVALID_UDISK_ID)
	{
#ifdef NEW_DEMO_FRAME
	#if(((!defined SUPPORT_CAS9)&&(!defined FTA_ONLY)&&(!defined SUPPORT_VMX_STD)&&(!defined SUPPORT_VMX))|| (defined MEDIAPLAYER_SUPPORT))
		win_media_player_init((mp_callback_func)(mp_apcallback));
		file_list_init_parameter();
		mp_udisk_id = 0; // only used to indicate media player is inited
	#endif	
#else
		mp_udisk_id = udisk_init(mp_udisk_id, (mp_callback_func)(mp_apcallback), __MM_MP_BUFFER_ADDR, __MM_MP_BUFFER_LEN);//TODO:Should be modified to function with paramater UDISK_ID
		file_list_init_parameter();
		if (mp_udisk_id == INVALID_UDISK_ID)
		{
			ASSERT(0);
			return -1;
		}
#endif
		DM_DEBUG("media player init\n");
	}
	return 0;
}

static int mp_disk_detach_proc()
{
	int vol_num, tot_vol_num = 0;
	int ret;
	
	DM_DEBUG("Enter %s() ...\n", __FUNCTION__);
	
	ret = dm_ioctl(DM_CMD1_GET_VOL_NUM, DM_CMD_PARAM(MNT_TYPE_USB, 0, 0), &vol_num, sizeof(int));
	if (ret == 0 && vol_num > 0)
		tot_vol_num += vol_num;

	ret = dm_ioctl(DM_CMD1_GET_VOL_NUM, DM_CMD_PARAM(MNT_TYPE_SD, 0, 0), &vol_num, sizeof(int));
	if (ret == 0 && vol_num > 0)
		tot_vol_num += vol_num;

	ret = dm_ioctl(DM_CMD1_GET_VOL_NUM, DM_CMD_PARAM(MNT_TYPE_IDE, 0, 0), &vol_num, sizeof(int));
	if (ret == 0 && vol_num > 0)
		tot_vol_num += vol_num;

	ret = dm_ioctl(DM_CMD1_GET_VOL_NUM, DM_CMD_PARAM(MNT_TYPE_SATA, 0, 0), &vol_num, sizeof(int));
	if (ret == 0 && vol_num > 0)
		tot_vol_num += vol_num;
	
	if (tot_vol_num <= 0)
	{
		ap_udisk_close();
	}

	return 0;
}

#ifdef _BUILD_USB_LOADER_
static int win_mp_detach_proc()
{
	return 0;
}
#else
extern int mp_get_cur_disk_name(char *name, int len);

// TODO: implement this function in win_filelist.c
static int win_mp_detach_proc()
{
	char cur_disk_name[8];
	BOOL b_exit_win_mp = FALSE;
	int disk_type = 0, disk_idx = 0, dm_ret = 0, vol_num = 0;

	if ((mp_get_cur_disk_name(cur_disk_name, 8) == 0) &&
		(STRLEN(cur_disk_name) == 3))
	{
		disk_type = diskNamePrefix2Type(cur_disk_name);
		disk_idx = (int)cur_disk_name[2] - 'a';
		dm_ret = dm_ioctl(DM_CMD2_GET_VOL_NUM, DM_CMD_PARAM(disk_type, disk_idx, 0),
							&vol_num, sizeof(int));
		if (dm_ret != 0 || vol_num <= 0)			
			win_delete_all_filelist();
	}
	
	if (!mp_in_win_filelist())
		return 0;

	DM_DEBUG("%s() system_state: %d\n", __FUNCTION__, system_state);
	
	if (!ap_mp_is_ready()) // exit menu, if all disks are detached
	{
		b_exit_win_mp = TRUE;
	}
	else if ((mp_get_cur_disk_name(cur_disk_name, 8) == 0) &&
			 (STRLEN(cur_disk_name) == 3))
	{
		if (dm_ret != 0 || vol_num <= 0)
		{	
			b_exit_win_mp = TRUE;
		}
	}
	else
	{
		b_exit_win_mp = TRUE;
	}

	if (b_exit_win_mp)
	{
		DM_DEBUG("disk detach in Media Player, enter main menu\n");
		// Alert here:Clear all menus may cuase unpredictable result,must be tested
		api_osd_mode_change(OSD_NO_SHOW);
		ap_clear_all_menus(); //clear all menu & Hidden osd show
		menu_stack_pop_all();
	
		image_restore_vpo_rect();
		ap_clear_all_message();
		api_set_system_state(SYS_STATE_NORMAL);
		ap_send_msg(CTRL_MSG_SUBTYPE_CMD_ENTER_ROOT,(UINT32)&g_win_mainmenu, FALSE);
	}
}
#endif

/******************************************************************************
 * for PVR
 ******************************************************************************/
 #ifdef _BUILD_USB_LOADER_
static void pvr_part_init_task(UINT32 param1, UINT32 param2)
{
}
static int pvr_part_init_task_create(struct pvr_register_info *info)
{
	return 1;
}
#else
static ID pvr_part_init_task_id = OSAL_INVALID_ID;
static struct pvr_register_info l_pvr_reg_info;

/* It will cost a long time when register PVR partitions and do read/write test.
 * In order not to block the control task, create pvr_part_init_task() to do that.
 */
static void pvr_part_init_task(UINT32 param1, UINT32 param2)
{
	struct pvr_register_info *info = (struct pvr_register_info *)param1;

	if (pvr_register(param1, 0) == SUCCESS)
		DM_DEBUG("pvr init %s to %d done!\n", info->mount_name, info->disk_usage);
	else
		DM_ERROR("pvr init %s to %d failed!\n", info->mount_name, info->disk_usage);

	pvr_part_init_task_id = OSAL_INVALID_ID;
}

static int pvr_part_init_task_create(struct pvr_register_info *info)
{
	OSAL_T_CTSK	task_attribute;

	if (pvr_part_init_task_id != OSAL_INVALID_ID)
	{
		DM_DEBUG("pvr_part_init_task() is running\n");
		return 1;
	}

	MEMCPY(&l_pvr_reg_info, info, sizeof(struct pvr_register_info));
	task_attribute.stksz	= 0x2000;
	task_attribute.quantum	= 10;
	task_attribute.itskpri	= OSAL_PRI_NORMAL;
	task_attribute.para1	= (UINT32)(&l_pvr_reg_info);
	task_attribute.para2	= 0;
	task_attribute.name[0]	= 'P';
	task_attribute.name[1]	= 'P';
	task_attribute.name[2]	= 'I';
	task_attribute.task 	= (FP)pvr_part_init_task;
	
	pvr_part_init_task_id = osal_task_create(&task_attribute);
	if (pvr_part_init_task_id == OSAL_INVALID_ID)
	{
		DM_ERROR("create pvr_part_init_task failed!\n");
		return -1;
	}
	
	DM_DEBUG("create pvr_part_init_task() to init pvr partitions\n");
	return 0;
}
#endif
static ID pvr_timer_id = OSAL_INVALID_ID;

static void dm_pvr_timer_handler()
{
	DM_DEBUG("waiting PVR default volumes times out\n");
	pvr_timer_id = OSAL_INVALID_ID;
	ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_USBREMOUNT, 0, FALSE);	
}

static void dm_pvr_timer_stop()
{
	api_stop_timer(&pvr_timer_id);
//	pvr_timer_id = OSAL_INVALID_ID;
}

static void dm_pvr_timer_start(UINT32 interval)
{
	if (pvr_timer_id == OSAL_INVALID_ID)
	{
		pvr_timer_id = api_start_timer("DM_PVR", interval, dm_pvr_timer_handler);
		ASSERT(pvr_timer_id != OSAL_INVALID_ID);
		DM_DEBUG("start to wait PVR default volumes\n");
	}
}
#ifdef _BUILD_USB_LOADER_
int pvr_select_part(char *rec_vol, char *tms_vol)
{
	return 0;
}

int pvr_change_part(const char *part_path, UINT8 part_mode)
{
	return 0;
}

static int pvr_disk_attach_proc(BOOL b_force)
{
	return 0;
}

static int pvr_disk_detach_proc()
{
	return 0;
}
static int win_pvr_detach_proc()
{
	return 0;
}
#else
/* select partitions for pvr to record or timeshift automatically */
int pvr_select_part(char *rec_vol, char *tms_vol)
{
	int i, j;
	char vol_path[16];
	struct statvfs buf;
	SYSTEM_DATA *sys_data = sys_data_get();
	DiskInfo *p_disk;

	if (rec_vol)
	{
		if ((sys_data->rec_disk[0] != 0) && (fs_statvfs(sys_data->rec_disk, &buf) >= 0))
			STRCPY(rec_vol, sys_data->rec_disk);
		else
			rec_vol[0] = 0;
	}
	
	if (tms_vol)
	{
		if ((sys_data->tms_disk[0] != 0) && (fs_statvfs(sys_data->tms_disk, &buf) >= 0))
			STRCPY(tms_vol, sys_data->tms_disk);
		else
			tms_vol[0] = 0;
	}

	MEMSET(vol_path, 0, 16);
	if ((rec_vol && rec_vol[0] == 0) || (tms_vol && tms_vol[0] == 0))
	{
		/* select the first volume for pvr */
		for (i = 0; i < MAX_USB_DISK_NUM; ++i)
		{
			if (vol_path[0] != 0)
				break;
			
			if ((p_disk = g_dm.UsbDisks[i]) == NULL)
				continue;
			
			for (j = 0; j < MAX_PARTS_IN_DISK; ++j)
			{
				if ((p_disk->parts[j].PartExist == 1) &&
					(p_disk->parts[j].FileSystemType != PED_FS_TYPE_NONE))
				{
					sprintf(vol_path, "/mnt/ud%c%c", i+'a', j+'1');
					break;
				}
			}
			
		}
		
		for (i = 0; i < MAX_IDE_DISK_NUM; ++i)
		{
			if (vol_path[0] != 0)
				break;
			
			if ((p_disk = g_dm.IdeDisks[i]) == NULL)
				continue;

			for (j = 0; j < MAX_PARTS_IN_DISK; ++j)
			{
				if ((p_disk->parts[j].PartExist == 1) &&
					(p_disk->parts[j].FileSystemType != PED_FS_TYPE_NONE))
				{
					sprintf(vol_path, "/mnt/hd%c%c", i+'a', j+'1');
					break;
				}
			}
		}
	}

	if (vol_path[0] != 0)
	{
		if (rec_vol && rec_vol[0] == 0)
			STRCPY(rec_vol, vol_path);
		
		if (tms_vol && tms_vol[0] == 0)
			STRCPY(tms_vol, vol_path);
	}

	if (rec_vol && rec_vol[0] != 0)
		DM_DEBUG("%s() select REC vol: %s\n", __FUNCTION__, rec_vol);

	if (tms_vol && tms_vol[0] != 0)
		DM_DEBUG("%s() select TMS vol: %s\n", __FUNCTION__, tms_vol);

	return 0;
}

/* change partition @part_path to @part_mode, for pvr */
int pvr_change_part(const char *part_path, UINT8 part_mode)
{
	struct dvr_HDD_info hdd_info;
	struct pvr_register_info pvr_reg_info;
	char rec_part[16], tms_part[16];
	enum PVR_DISKMODE cur_pvr_mode;
	SYSTEM_DATA *sys_data;
	BOOL register_part = FALSE;
	int ret = 0;

	if (part_path == NULL || part_path[0] == 0)
		return -1;

	DM_DEBUG("%s() change %s to %d\n", __FUNCTION__, part_path, part_mode);
	sys_data = sys_data_get();
	cur_pvr_mode = pvr_get_cur_mode(rec_part, tms_part);

	MEMSET(&pvr_reg_info, 0, sizeof(struct pvr_register_info));
	STRCPY(pvr_reg_info.mount_name, part_path);
	pvr_reg_info.disk_usage = part_mode;
	pvr_reg_info.sync = 1;
	
	switch (part_mode)
	{
		case PVR_REC_AND_TMS_DISK:
			if (cur_pvr_mode == PVR_DISK_REC_AND_TMS)
			{
				pvr_detach_part(rec_part, PVR_REC_AND_TMS_DISK);
			}
			else
			{
				pvr_detach_part(rec_part, PVR_REC_ONLY_DISK);
				pvr_detach_part(tms_part, PVR_TMS_ONLY_DISK);
			}
			
			pvr_reg_info.init_list = 1;
#ifndef PVR_SPEED_PRETEST_DISABLE  /* --doy, 2011-3-21*/
			pvr_reg_info.check_speed = 1;
#endif
			if (pvr_register((UINT32)&pvr_reg_info, 0) != SUCCESS)
			{
				api_pvr_clear_up_all();
				ret = -1;
			}
			STRCPY(sys_data->rec_disk, part_path);
			STRCPY(sys_data->tms_disk, part_path);
			sys_data_save(0);
			break;
		case PVR_REC_ONLY_DISK:
			if ((STRLEN(rec_part) > 0) && (STRCMP(rec_part, part_path) == 0))
			{
				 // same partition
				if ((cur_pvr_mode == PVR_DISK_ONLY_REC) ||
					(cur_pvr_mode == PVR_DISK_REC_WITH_TMS))
				{
					break;
				}
				else if (cur_pvr_mode == PVR_DISK_REC_AND_TMS)
				{
					pvr_set_disk_use(PVR_REC_ONLY_DISK, part_path);
				}
				else
				{
					DM_DEBUG("rec_part: %s, mount_name: %s, mode: %d, %d\n",
							 rec_part, part_path, cur_pvr_mode, part_mode);
					register_part = TRUE;
					//SDBBP();
				}
			}
			else // diff partition
			{
				register_part = TRUE;
				if (cur_pvr_mode == PVR_DISK_REC_AND_TMS)
				{
					pvr_set_disk_use(PVR_TMS_ONLY_DISK, tms_part);
				}

				if ((cur_pvr_mode == PVR_DISK_ONLY_REC) ||
					(cur_pvr_mode == PVR_DISK_REC_WITH_TMS))
				{
					pvr_detach_part(rec_part, PVR_REC_ONLY_DISK);
				}

				if ((STRCMP(tms_part, part_path) == 0) && 
					((cur_pvr_mode == PVR_DISK_ONLY_TMS) ||
					 (cur_pvr_mode == PVR_DISK_REC_WITH_TMS)))
				{
					pvr_detach_part(tms_part, PVR_TMS_ONLY_DISK);
				}
			}
			if (register_part)
			{
				pvr_reg_info.init_list = (part_mode != PVR_TMS_ONLY_DISK);
#ifndef PVR_SPEED_PRETEST_DISABLE  /* --doy, 2011-3-21*/
				pvr_reg_info.check_speed = 1;
#endif
				//osal_task_sleep(1000); // wait for pvr cleanup finished
				if (pvr_register((UINT32)&pvr_reg_info, 0) != SUCCESS)
				{
					ret = -1;
				}
			}
			STRCPY(sys_data->rec_disk, part_path);
			if(!STRCMP(sys_data->tms_disk, part_path))
				STRCPY(sys_data->tms_disk, "");
			sys_data_save(0);
			break;
		case PVR_TMS_ONLY_DISK:				
			if ((STRLEN(tms_part) > 0) && (STRCMP(tms_part, part_path) == 0))
			{
				 // same partition
				if ((cur_pvr_mode == PVR_DISK_ONLY_TMS) ||
					(cur_pvr_mode == PVR_DISK_REC_WITH_TMS))
				{
					break;
				}
				else if (cur_pvr_mode == PVR_DISK_REC_AND_TMS)
				{
					pvr_set_disk_use(PVR_TMS_ONLY_DISK, part_path);
				}
				else
				{
					DM_DEBUG("rec_part: %s, mount_name: %s, mode: %d, %d\n",
							 rec_part, part_path, cur_pvr_mode, part_mode);
					register_part = TRUE;
					//SDBBP();
				}
			}
			else // diff partition
			{
				register_part = TRUE;
				if (cur_pvr_mode == PVR_DISK_REC_AND_TMS)
				{
					pvr_set_disk_use(PVR_REC_ONLY_DISK, rec_part);
				}

				if ((cur_pvr_mode == PVR_DISK_ONLY_TMS) ||
					(cur_pvr_mode == PVR_DISK_REC_WITH_TMS))
				{
					pvr_detach_part(tms_part, PVR_TMS_ONLY_DISK);
				}

				if ((STRCMP(rec_part, part_path) == 0) && 
					((cur_pvr_mode == PVR_DISK_ONLY_REC) ||
					 (cur_pvr_mode == PVR_DISK_REC_WITH_TMS)))
				{
					pvr_detach_part(rec_part, PVR_REC_ONLY_DISK);
				}
			}

			if (register_part)
			{
				pvr_reg_info.init_list = (part_mode != PVR_TMS_ONLY_DISK);
#ifndef PVR_SPEED_PRETEST_DISABLE  /* --doy, 2011-3-21*/
				pvr_reg_info.check_speed = 1;
#endif
				//osal_task_sleep(1000); // wait for pvr cleanup finished
				if (pvr_register((UINT32)&pvr_reg_info, 0) != SUCCESS)
				{
					ret = -1;
				}
			}
			STRCPY(sys_data->tms_disk, part_path);
			if(!STRCMP(sys_data->rec_disk, part_path))
				STRCPY(sys_data->rec_disk, "");
			sys_data_save(0);
			break;
		default:
			break;
	}
	
	api_pvr_adjust_tms_space();
	pvr_get_HDD_info(&hdd_info);
	api_pvr_check_level(&hdd_info);
	return ret;
}

/* Register volume for PVR record or timeshift.
 * 	1. it should be call when volume mounted
 *  @b_force: force to select volumes for pvr, don't wait other devices
 */
static int pvr_disk_attach_proc(BOOL b_force)
{
	SYSTEM_DATA *sys_data = sys_data_get();;
	enum PVR_DISKMODE pvr_mode;
	char rec_vol[16], tms_vol[16];
	struct statvfs buf;
	struct pvr_register_info pvr_reg_info;
	BOOL b_wait = TRUE;

	if (pvr_part_init_task_id != OSAL_INVALID_ID)
	{
		DM_DEBUG("pvr partition %s is initializing to %d\n",
			l_pvr_reg_info.mount_name, l_pvr_reg_info.disk_usage);
		return 0;
	}
	
	DM_DEBUG("Enter %s(%d) ...\n", __FUNCTION__, b_force);
	pvr_mode = pvr_get_cur_mode(rec_vol, tms_vol);
	switch (pvr_mode)
	{
		case PVR_DISK_REC_AND_TMS:
		case PVR_DISK_REC_WITH_TMS:
			DM_DEBUG("pvr partition already init (%s, %s)\n", rec_vol, tms_vol);
			return 0;
		case PVR_DISK_ONLY_REC:
			/* check if tms volume valid */
			DM_DEBUG("pvr rec partition already init (%s, %s)\n", rec_vol, tms_vol);
			if ((tms_vol[0] == 0) && (STRLEN(sys_data->tms_disk) > 0) &&
				(fs_statvfs(sys_data->tms_disk, &buf) >= 0))
			{
				MEMSET(&pvr_reg_info, 0, sizeof(struct pvr_register_info));
				STRCPY(pvr_reg_info.mount_name, sys_data->tms_disk);
				pvr_reg_info.disk_usage = PVR_TMS_ONLY_DISK;
				pvr_reg_info.sync = 1;
				pvr_reg_info.init_list = 0;
#ifndef PVR_SPEED_PRETEST_DISABLE  /* --doy, 2011-3-21*/
				pvr_reg_info.check_speed = 1;
#endif
				pvr_part_init_task_create(&pvr_reg_info);
			}
			return 0;
		case PVR_DISK_ONLY_TMS:
			/* check if rec volume valid */
			DM_DEBUG("pvr tms partition already init (%s, %s)\n", rec_vol, tms_vol);
			if ((rec_vol[0] == 0) && (STRLEN(sys_data->rec_disk) > 0) &&
				(fs_statvfs(sys_data->rec_disk, &buf) >= 0))
			{
				MEMSET(&pvr_reg_info, 0, sizeof(struct pvr_register_info));
				STRCPY(pvr_reg_info.mount_name, sys_data->rec_disk);
				pvr_reg_info.disk_usage = PVR_REC_ONLY_DISK;
				pvr_reg_info.sync = 1;
				pvr_reg_info.init_list = 1;
#ifndef PVR_SPEED_PRETEST_DISABLE  /* --doy, 2011-3-21*/
				pvr_reg_info.check_speed = 1;
#endif
				pvr_part_init_task_create(&pvr_reg_info);
			}
			return 0;
		default:
			DM_DEBUG("pvr partition not init\n");
			break;
	}

	STRCPY(rec_vol, sys_data->rec_disk);
	STRCPY(tms_vol, sys_data->tms_disk);
	rec_vol[1] = tms_vol[1] = 'd';
	rec_vol[2] = tms_vol[2] = 'e';
	rec_vol[3] = tms_vol[3] = 'v';
	rec_vol[8] = tms_vol[8] = '\0';  // temp for disk path, eg. "/dev/uda"
	
	if ((rec_vol[0] == 0 && tms_vol[0] == 0) ||
		(tms_vol[0] == 0 && fs_statvfs(rec_vol, &buf) >= 0) ||
		(rec_vol[0] == 0 && fs_statvfs(tms_vol, &buf) >= 0) ||
		(fs_statvfs(rec_vol, &buf) >= 0 && fs_statvfs(tms_vol, &buf) >= 0))
	{
		b_wait = FALSE;
	}
	
	if (b_force || !b_wait)
	{
		// register rec and tms partition
		dm_pvr_timer_stop();
		DM_DEBUG("To register volume for PVR ...\n");
		pvr_select_part(rec_vol, tms_vol);

		if (STRLEN(tms_vol) > 0 && STRCMP(rec_vol, tms_vol) != 0)
		{
			MEMSET(&pvr_reg_info, 0, sizeof(struct pvr_register_info));
			STRCPY(pvr_reg_info.mount_name, tms_vol);
			pvr_reg_info.disk_usage = PVR_TMS_ONLY_DISK;
			pvr_reg_info.init_list = 0;
#ifndef PVR_SPEED_PRETEST_DISABLE  /* --doy, 2011-3-21*/
			pvr_reg_info.check_speed = 1;
#endif
			if (STRLEN(rec_vol) > 0)
			{	// init partition takes no time when (sync == 0), call pvr_register() directly
				pvr_reg_info.sync = 0;
				pvr_register((UINT32)&pvr_reg_info, 0);
			}
			else
			{
				pvr_reg_info.sync = 1;
				pvr_part_init_task_create(&pvr_reg_info);
			}
		}
		
		if (STRLEN(rec_vol) > 0)
		{
			MEMSET(&pvr_reg_info, 0, sizeof(struct pvr_register_info));
			STRCPY(pvr_reg_info.mount_name, rec_vol);
			pvr_reg_info.disk_usage = (!STRCMP(rec_vol, tms_vol)) ? PVR_REC_AND_TMS_DISK : PVR_REC_ONLY_DISK;
			pvr_reg_info.sync = 1;
			pvr_reg_info.init_list = 1;
#ifndef PVR_SPEED_PRETEST_DISABLE  /* --doy, 2011-3-21*/
			pvr_reg_info.check_speed = 1;
#endif
			pvr_part_init_task_create(&pvr_reg_info);
		}

		if (rec_vol)
			STRCPY(sys_data->rec_disk, rec_vol);

		if (tms_vol)
			STRCPY(sys_data->tms_disk, tms_vol);

		sys_data_save(0);
	}
	else /* we need to wait default disk ready */
	{
		dm_pvr_timer_start(5000);
	}
	
	return 0;
}

/* Un-register pvr volume if necessary
 * 	1. it should be call when disk detach
 */
static int pvr_disk_detach_proc()
{
	struct statvfs buf;
	enum PVR_DISKMODE pvr_mode;
	char rec_vol[16], tms_vol[16], initing_vol[16];
	UINT8 initing_vol_usage = 0;
	BOOL b_pvr_part_detached = FALSE;

	DM_DEBUG("Enter %s() ...\n", __FUNCTION__);

	if (pvr_part_init_task_id != OSAL_INVALID_ID)
	{
		DM_DEBUG("pvr partition %s is initializing to %d\n",
			l_pvr_reg_info.mount_name, l_pvr_reg_info.disk_usage);
		
		STRCPY(initing_vol, l_pvr_reg_info.mount_name);
		initing_vol_usage = l_pvr_reg_info.disk_usage;
	}
	else
	{
		initing_vol[0] = 0;
	}
	
	pvr_mode = pvr_get_cur_mode(rec_vol, tms_vol);

	BOOL rec_vol_detach = ((rec_vol[0] != 0) && (fs_statvfs(rec_vol, &buf) < 0));
	BOOL tms_vol_detach = ((tms_vol[0] != 0) && (fs_statvfs(tms_vol, &buf) < 0));

	if ((initing_vol[0] != 0) && (fs_statvfs(initing_vol, &buf) < 0))
	{
		if (STRCMP(initing_vol, rec_vol) != 0)
		{
			DM_DEBUG("pvr detach initializing volume %s\n", initing_vol);
			pvr_detach_part(initing_vol, initing_vol_usage);
			b_pvr_part_detached = TRUE;
		}
		initing_vol[0] = 0;
	}

	if (rec_vol_detach || tms_vol_detach)
	{
		/* a disk that used by pvr is detached */
		if (STRCMP(rec_vol, tms_vol) == 0)
		{
			DM_DEBUG("pvr detach %s\n", rec_vol);
			pvr_detach_part(rec_vol, PVR_REC_AND_TMS_DISK);
			b_pvr_part_detached = TRUE;
		}
		else
		{
			if (rec_vol_detach)
			{
				DM_DEBUG("pvr detach %s\n", rec_vol);
				pvr_detach_part(rec_vol, PVR_REC_ONLY_DISK);
				b_pvr_part_detached = TRUE;
			}

			if (tms_vol_detach)
			{
				DM_DEBUG("pvr detach %s\n", tms_vol);
				pvr_detach_part(tms_vol, PVR_TMS_ONLY_DISK);
				b_pvr_part_detached = TRUE;
			}
		}
	}

	if ((pvr_get_cur_mode(rec_vol, tms_vol) == PVR_DISK_INVALID) &&
		(initing_vol[0] == 0))
	{
		DM_DEBUG("pvr detach all volume, do clean up!\n");
		api_pvr_clear_up_all();
	}

	if (b_pvr_part_detached)
	{
		struct dvr_HDD_info hdd_info;
		pvr_get_HDD_info(&hdd_info);
		api_pvr_check_level(&hdd_info);
	}
	return 0;
}

static int win_pvr_detach_proc()
{
	char rec_vol[16];
	
	if (system_state != SYS_STATE_USB_PVR)
	{
		return 0;
	}

	rec_vol[0] = 0;
	pvr_get_cur_mode(rec_vol, NULL);
	if (rec_vol[0] == 0)
	{
		DM_DEBUG("disk detach in PVR record manager, enter main menu\n");
		// Alert here:Clear all menus may cuase unpredictable result,must be tested
		api_osd_mode_change(OSD_NO_SHOW);
		ap_clear_all_menus(); //clear all menu & Hidden osd show
		menu_stack_pop_all();
	
		image_restore_vpo_rect();
		ap_clear_all_message();
		api_set_system_state(SYS_STATE_NORMAL);
		api_pvr_set_back2menu_flag(FALSE);
		dmx_start((struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, 0));
 #ifdef NEW_DEMO_FRAME
		dmx_start((struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, 1));
 #endif
		ap_send_msg(CTRL_MSG_SUBTYPE_CMD_ENTER_ROOT,(UINT32)&g_win_mainmenu, FALSE);
	}
}
#endif

/******************************************************************************
 * other functions
 ******************************************************************************/
/* show device connect/disconnect message */
#define DM_HINT_CONNECT			0
#define DM_HINT_DISCONNECT		1
static void dm_disk_show_hint(UINT32 dev_type, UINT32 dev_id, UINT32 hint_type)
{
	UINT8 i;
	char hint[128];
	UINT8 back_saved;

#if defined( SUPPORT_CAS9) //||defined (SUPPORT_CAS7) 
	if(get_mmi_showed()!=0)//mmi pri is high than this popup
		return;
#elif defined(SUPPORT_CAS_A)
	if(api_abel_mmi_check_mmi_in_progress())
	{
		/* Abel user confirm dialog(ex. parental control, DIALOG_6)'s priority is higher than this popup*/
		DM_DEBUG("%s(): Abel user confirm dialog(ex. parental control, DIALOG_6)'s priority is higher than this popup \n", __FUNCTION__);
		return;
	}	
#endif

#if defined( SUPPORT_VMX_STD) ||defined (SUPPORT_VMX)
	if(vmx_api_get_osm_show()||api_osm_confirm_menu_exist())
	{
		//VMX OSM pri is higher than DVB status menu
		VMX_API_PRINTF("%s-Skip due to VMX OSM\n",__FUNCTION__);
		return;
	}
#endif

	switch (dev_type)
	{
		case MNT_TYPE_USB:
			sprintf(hint, "USB disk %c", dev_id+'A');
			break;
		case MNT_TYPE_SD:
			sprintf(hint, "SD card");
			break;
		case MNT_TYPE_IDE:
			sprintf(hint, "IDE disk");
			break;
		case MNT_TYPE_SATA:
			sprintf(hint, "SATA disk");
			break;
		default:
			return;
	}

	switch (hint_type)
	{
		case DM_HINT_CONNECT:
			strcat(hint, " connected");
			break;
		case DM_HINT_DISCONNECT:
			strcat(hint, " disconnected");
			break;
		default:
			return;
	}
	
	DM_DEBUG("%s() show message: %s\n", __FUNCTION__, hint);
	win_compopup_init(WIN_POPUP_TYPE_SMSG);
	win_compopup_set_msg_ext(hint, NULL, 0);
   // #ifdef SUPPORT_CAS9 jackqin did
   #if defined( SUPPORT_CAS9) ||defined (SUPPORT_CAS7) || defined(SUPPORT_CAS_A)
        #ifndef SD_UI
            win_compopup_set_frame(290, 250, 448, 100);
    	#else
			win_compopup_set_frame(150, 200, 300, 80);
    	#endif
    #endif
#ifdef MULTIVIEW_SUPPORT
    if((system_state == SYS_STATE_9PIC)||(system_state == SYS_STATE_4_1PIC))
        win_compopup_set_frame(390, 260, 500, 200);
#endif
#ifdef _INVW_JUICE   //0711 release
	if (INVIEW_pause(TRUE, 0) == true) {
	  win_compopup_open_ext(&back_saved);	
  	  osal_task_sleep(1000);
        }
#else
	win_compopup_open_ext(&back_saved);	
	osal_task_sleep(1000);
#endif
	win_compopup_smsg_restoreback();
}

PRESULT ap_mp_message_proc(UINT32 msg_type, UINT32 msg_code)
{
	UINT32 dev_type = DM_DEV_TYPE(msg_code);
	UINT32 dev_id   = DM_DEV_ID(msg_code);
	
#ifdef DVR_PVR_SUPPORT
	ap_pvr_message_proc(msg_type, msg_code, 0);
#endif
	
	if (msg_type == CTRL_MSG_SUBTYPE_STATUS_USBMOUNT)
	{
		if (dev_type != MNT_TYPE_SD)
		{
    	    if(dev_id ==0)//summic add for USB-Disk boot order 
    			pvr_disk_attach_proc(FALSE);
		}
#if 1//ChengYu@20140217, factory mode implement
		if (Factory_Mode_Get_Flag()==TRUE)
			set_factory_USB_result(TRUE);
#endif
		mp_disk_attach_proc();
		win_disk_info_update(TRUE);
//		if(!win_msg_popup_opend())
		      dm_disk_show_hint(dev_type, dev_id, DM_HINT_CONNECT);
		ap_send_msg(CTRL_MSG_SUBTYPE_CMD_STO, USB_STATUS_OVER, FALSE);
	}
	else if (msg_type == CTRL_MSG_SUBTYPE_STATUS_USBREMOUNT)
	{
		pvr_disk_attach_proc(TRUE);
	}
	else if (msg_type == CTRL_MSG_SUBTYPE_STATUS_USBUNMOUNT)
	{
		if (dev_type != MNT_TYPE_SD)
		{
			pvr_disk_detach_proc();
		}
		mp_disk_detach_proc();
		win_disk_info_update(TRUE);
//		if(!win_msg_popup_opend())
		      dm_disk_show_hint(dev_type, dev_id, DM_HINT_DISCONNECT);
		if (dev_type != MNT_TYPE_SD)
		{
			win_pvr_detach_proc();	// must call after pvr_disk_detach_proc()
		}
		win_mp_detach_proc(); // must call after mp_disk_detach_proc()

		win_delete_filelist(dev_id);
		ap_send_msg(CTRL_MSG_SUBTYPE_CMD_STO, USB_STATUS_OVER, FALSE);
	}
	else if (msg_type == CTRL_MSG_SUBTYPE_STATUS_USBREFLASH)
	{
		ap_udisk_close();
#ifdef NEW_DEMO_FRAME
		win_media_player_init((mp_callback_func)(mp_apcallback));
		mp_udisk_id = 0;
#else
        udisk_set_ingore_dir(PVR_ROOT_DIR);
 		mp_udisk_id = udisk_init(mp_udisk_id,(mp_callback_func)(mp_apcallback), __MM_MP_BUFFER_ADDR, __MM_MP_BUFFER_LEN);
#endif
	}
	return PROC_LOOP;
}

void fs_apcallback(UINT32 event_type, UINT32 param)
{
	UINT32 dev_type     = MNT_DEV_TYPE(param);
	UINT32 dev_id       = MNT_DEV_ID(param);
	UINT32 mount_status = MNT_STATUS(param);

	DM_DEBUG("%s(): (%d, %d), (%d, %d)\n",__FUNCTION__, dev_type, dev_id, event_type, mount_status);

	switch (event_type)
	{
		case MP_FS_MOUNT:
			if ((mount_status == MNT_MOUNT_OK) || (mount_status == MNT_FAILED))
			{
				dm_update(dev_type, dev_id);
			}
			if (mount_status == MNT_MOUNT_OK)
			{
				DM_DEBUG("send ap mount msg (%d, %d)\n", dev_type, dev_id);
				ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_USBMOUNT, DM_MSG_CODE(dev_type, dev_id), FALSE);
			}
			break;
		case MP_FS_UNMOUNT:
//			if ((mount_status == UNMNT_UNMOUNT_OK) || (mount_status == UNMNT_UNMOUNT))
			if (mount_status == UNMNT_UNMOUNT_OK)
			{
				//fixed bug:BUG00446
				if(system_state == SYS_STATE_TEXT)
				{
					// in order to exit ttx first!
					UINT32 hkey;
					ap_vk_to_hk(0, V_KEY_TEXT, &hkey);
					ap_send_msg(CTRL_MSG_SUBTYPE_KEY, hkey, TRUE);		
					osal_task_sleep(500);
				}
				
				dm_update(dev_type, dev_id);
				DM_DEBUG("send ap unmount msg (%d, %d)\n", dev_type, dev_id);
				ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_USBUNMOUNT, DM_MSG_CODE(dev_type, dev_id), FALSE);
			}
			break;
		default:
			break;
	}
}
#ifdef _BUILD_USB_LOADER_
void mp_apcallback(UINT32 event_type,UINT32 param)
{
}
#else
void mp_apcallback(UINT32 event_type,UINT32 param)
{
//	DM_DEBUG("%s(): event_type = %d, param=%d\n",__FUNCTION__, event_type, param);
	POBJECT_HEAD win_top = menu_stack_get_top();

	if((win_top == (POBJECT_HEAD)&g_win_imageslide) 
		|| (win_top == (POBJECT_HEAD)&g_win_usb_filelist)
		|| (win_top == (POBJECT_HEAD)&g_win_imagepreview)
		|| (win_top == (POBJECT_HEAD)&g_win_mpeg_player)
		|| (win_top == (POBJECT_HEAD)&g_win_record)
		|| (win_top == (POBJECT_HEAD)&g_win_volume)
		|| (win_top == (POBJECT_HEAD)&g_cnt_chapter)
		|| (win_top == (POBJECT_HEAD)&win_subt_set_con)
		|| (win_top == (POBJECT_HEAD)&g_cnt_subtitle)
	  )
	{
		switch(event_type)
		{
		case MP_IMAGE_PLAYBACK_END:
//			ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_IMAGEOVER,0,FALSE);//when play jpg+mp3,should not clear buff
			ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_IMAGEOVER,osal_get_tick(),FALSE);//when play jpg+mp3,should not clear buff
			break;
		case MP_MUSIC_PLAYBACK_END:
			ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_MP3OVER,0,FALSE);
			break;
		case MP_IMAGE_DECODE_PROCESS:
			ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_JPEG_DEC_PROCESS,param,FALSE);
			break;
		case MP_IMAGE_DECODER_ERROR:
			ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_JPEG_DEC_ERR,param,FALSE);
			break;
	    case MP_VIDEO_PLAYBACK_END:
			ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_VIDEO_OVER,param,TRUE);
			break;
        case MP_VIDEO_BUILD_IDX_TBL:
            ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_BUILD_IDX, param, FALSE);
            break;
		case MP_VIDEO_PARSE_END:
			ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_PARSE_END,param,TRUE);
			break;		
		case MP_VIDEO_DECODER_ERROR:
			ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_VIDEO_DEC_ERR,param,TRUE);
			break;	
		case MP_FS_IDE_MOUNT_NAME:
			STRCPY((char *)param, IDE_MOUNT_NAME);
			break;
		case MP_FS_USB_MOUNT_NAME:
			STRCPY((char *)param, USB_MOUNT_NAME);
			break;
		default:
			break;	
		}
	}
#ifdef _INVW_JUICE  //v0.1.4
	else
	{
		mp_callback_func mp_alternative_cb = win_media_network_player_get_alternative_callback();
		if(mp_alternative_cb)
		{
			mp_alternative_cb(event_type, param);
		}
	}
#endif
}
#endif

void storage_switch_sd_ide(UINT8 sd_active, BOOL first)
{
    if (sd_active)
    {
		if (!first)
		{
#ifdef IDE_SUPPORT
			ide_disable();
#endif
		}
#ifdef SDIO_SUPPORT
        BoardCfg* cfg = get_board_cfg();
        sd_enable(cfg->sdio_cs->position, cfg->sdio_cs->polar, cfg->sdio_detect->position, cfg->sdio_lock->position);
        sd_init();
#endif
		DM_DEBUG("storage device : sdio active\n");
    }
    else
    { 
		if (!first)
		{
#ifdef SDIO_SUPPORT
			sd_disable();
#endif
		}
#ifdef IDE_SUPPORT
        ide_enable(25, 1); 
        ide_init();
#endif
		DM_DEBUG("storage device : hdd(ide) active\n");
    }	
}

BOOL storage_switch_sd_ide_proc(UINT8 sd_active, BOOL first)
{
	char hint[64];
    UINT8 back_saved;
    win_popup_choice_t choice = WIN_POP_CHOICE_YES;
	
	if (first)
	{
		UINT32 cnt = osal_get_tick();
		win_compopup_init(WIN_POPUP_TYPE_SMSG);
		sprintf(hint, "Please wait %s initial",sd_active?"SD Card":"Hard Disk");
		win_compopup_set_msg(hint, NULL, 0);
		win_compopup_open();
		storage_switch_sd_ide(sd_active, TRUE);
		while(osal_get_tick()-cnt < 2000)
		{
			osal_task_sleep(10);
		}
		win_msg_popup_close();
		return TRUE;
	}
	else
	{
		win_compopup_init(WIN_POPUP_TYPE_OKNO);
		sprintf(hint, "Are you sure to switch to %s?",sd_active?"SD Card":"Hard Disk");
		win_compopup_set_msg(hint, NULL, 0);		
		win_compopup_set_default_choice(WIN_POP_CHOICE_NO);
		choice = win_compopup_open_ext(&back_saved);
		if (choice == WIN_POP_CHOICE_YES)
		{
			win_compopup_init(WIN_POPUP_TYPE_SMSG);
			win_compopup_set_msg("Please wait, maybe it will take a long time!", NULL, 0);
			win_compopup_open();
			storage_switch_sd_ide(sd_active, first);
			sys_data_set_sd_ide_statue(sd_active);
			win_msg_popup_close();
			return TRUE;
		}
	}

	return FALSE;
}


#ifdef USB_SAFELY_REMOVE_SUPPORT
BOOL usb_remove_safely_by_hotkey()
{
	int disk_num, tot_disk_num = 0;
	char disk_name[8];
	int ret;
	UINT32 choice;
	UINT8 disk_sel;
	UINT8 back_saved;
	POBJECT_HEAD topmenu;
		
	ret = dm_ioctl(DM_CMD1_GET_DISK_NUM, DM_CMD_PARAM(MNT_TYPE_USB, 0, 0), &disk_num, sizeof(int));
	if (ret == 0 && disk_num > 0)
		tot_disk_num += disk_num;

	ret = dm_ioctl(DM_CMD1_GET_DISK_NUM, DM_CMD_PARAM(MNT_TYPE_SD, 0, 0), &disk_num, sizeof(int));
	if (ret == 0 && disk_num > 0)
		tot_disk_num += disk_num;

	ret = dm_ioctl(DM_CMD1_GET_DISK_NUM, DM_CMD_PARAM(MNT_TYPE_SATA, 0, 0), &disk_num, sizeof(int));
	if (ret == 0 && disk_num > 0)
		tot_disk_num += disk_num;

	if (tot_disk_num <= 0)
	{
		return TRUE;
	}
	api_inc_wnd_count();
	ID timer_id = win_compopup_start_send_key_timer(V_KEY_EXIT, 10000, TIMER_ALARM); // exit popup if no action in 5s
	choice = win_disk_operate_open(OPERATE_TYPE_DISK_REMOVE, &disk_sel);
	api_stop_timer(&timer_id);
	
	if ((topmenu = menu_stack_get_top()) != NULL)
		OSD_TrackObject(topmenu, C_DRAW_SIGN_EVN_FLG | C_UPDATE_ALL);
	
	if (!choice)
	{
		api_dec_wnd_count();
		return TRUE;
	}
	else
	{
		win_removable_disk_get_name_str(disk_sel, disk_name);
	}
		
#ifdef DVR_PVR_SUPPORT
	enum PVR_DISKMODE pvr_mode;
	char rec_vol[16], tms_vol[16];
	struct statvfs buf;

	pvr_mode = pvr_get_cur_mode(rec_vol, tms_vol);

	if (api_pvr_is_record_active() && (STRLEN(rec_vol) == 9) &&
		(strncmp(disk_name, &rec_vol[5], 3) == 0))
	{
		win_compopup_init(WIN_POPUP_TYPE_OK);
	    win_compopup_set_msg("USB safely remove error, please stop recording first!", NULL, 0);
	    win_compopup_open_ext(&back_saved);
		api_dec_wnd_count();
		return TRUE;
	}

	if (api_pvr_is_playing())
	{
		BOOL b_can_remove = TRUE;
		if ((pvr_info.pvr_state == PVR_STATE_TMS_PLAY) &&
			(STRLEN(tms_vol) == 9) && (strncmp(disk_name, &tms_vol[5], 3) == 0))
		{
			b_can_remove = FALSE;
		}
		else if ((pvr_info.pvr_state != PVR_STATE_TMS_PLAY) &&
				 (STRLEN(rec_vol) == 9) && (strncmp(disk_name, &rec_vol[5], 3) == 0))
		{
			b_can_remove = FALSE;
		}

		if (!b_can_remove)
		{
			win_compopup_init(WIN_POPUP_TYPE_OK);
		    win_compopup_set_msg("USB safely remove error, please stop playing first!", NULL, 0);
		    win_compopup_open_ext(&back_saved);
			api_dec_wnd_count();
			return TRUE;
		}
	}

	if (pvr_info.pvr_state == PVR_STATE_TMS)
	{
		api_pvr_tms_proc(FALSE);
		fs_sync(tms_vol);
	}
#endif

#ifdef USB_SUPPORT_HUB
	/* remove disk */
	int disk_type = diskNamePrefix2Type(disk_name);
	if (disk_type == MNT_TYPE_USB)
	{
		char dev_path[16];
		int node_id, fd;
		sprintf(dev_path, "/dev/%s", disk_name);
		fd = fs_open(dev_path, O_RDONLY, 0);
		ret = fs_ioctl(fd, IOCTL_GET_NODEID, &node_id, sizeof(int));
		fs_close(fd);

		if (ret == 0)
			usbd_safely_remove_ex(node_id);
	}
#ifdef SDIO_SUPPORT
	else if (disk_type == MNT_TYPE_SD)
	{
		sd_notify(0);
	}
#endif
#ifdef SATA_SUPPORT
	else if (disk_type == MNT_TYPE_SATA)
	{
		sata_notify(0, 0);
	}
#endif
#else
	usbd_safely_remove();
#endif
	
	api_dec_wnd_count();
	return TRUE;
}

BOOL api_usb_device_safely_remove(void)
{
#ifdef DVR_PVR_SUPPORT
    if (pvr_info.pvr_state != PVR_STATE_IDEL)
        return FALSE;
#endif

	return usb_remove_safely_by_hotkey();
}

#endif /* USB_SAFELY_REMOVE_SUPPORT */

#endif /* DISK_MANAGER_SUPPORT */
